package com.woniuxy.shiro.utils;

import com.auth0.jwt.JWT;
import com.woniuxy.entity.RbacManager;
import com.woniuxy.entity.RbacPerm;
import com.woniuxy.service.RbacPermService;
import com.woniuxy.service.impl.UserService;
import com.woniuxy.utils.JWTUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @author: mayuhang  <br/>
 * Date: 2021/4/23:0:02  <br/>
 * Description:自定义域  自己写登录验证 和授权
 */
@Configuration
public class MyRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;
    @Autowired
    RbacPermService rbacPermService;
    @Autowired
    RedisTemplate redisTemplate;
    @Override
    public void setName(String name){
        super.setName("myRealm");
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        //让这个域 支持我们的jwt认证  而不是 用 UsernamePasswordToken
       return token instanceof MyJsonWebToken;
    }

    /**
     * 授权信息
     * 在前后端不分离的情况下, 在html页面使用<shiro>|后端使用shiro的@checkRole,@checkPermission相关注解才能触发
     * 前后端分离的模式, 就直接用注解验证权限即可, 根据需求来
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("授权:"+principals.toString());
        System.out.println("token:"+principals.getPrimaryPrincipal().toString());
        //根据自己写是MyJsonWebToken这个实体类 自己重写的方法有关
        String  token = (String) principals.getPrimaryPrincipal();
        //userName获取成功后  这里都改为 去redis中获取用户对象
        String userName = JWTUtil.getUserName(token);
        //去数据库获取对应的角色
        RbacManager user = userService.getUser(userName);
        //一个用户绑定的一个角色
        Integer roleId = user.getRoleId();
        //通过角色 去数据库查询所有权限
        List<RbacPerm> forRole = rbacPermService.findForRole(roleId+"");
        Set<String> perms = new HashSet<>();
        if (forRole!=null) {
            for (RbacPerm perm : forRole) {
                if (perm.getCode() != null) {
                    perms.add(perm.getCode());
                }
            }
        }
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole(roleId+"");
        simpleAuthorizationInfo.setStringPermissions(perms);
        //去数据库获取对应的权限
        return simpleAuthorizationInfo;
    }
    /**
     * 身份认证方法
     * 需要在用户登录系统时触发
     * 该方法将是我们主要的方法, 流程是登录后, 携带token 与权限信息 发送到 vue中 存储浏览器
     * 在页面渲染时,直接传入菜单和 页面按钮显示权限
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException {
        System.out.println("MyRealm.doGetAuthenticationInfo:"+auth.getPrincipal());
        String token = (String) auth.getPrincipal();
        Long expire = redisTemplate.getExpire(token, TimeUnit.SECONDS);
        System.out.println("这个token还有"+expire+"秒过期^ ^");
        if (expire<6000) {
            //token续期
            redisTemplate.expire(token, 6000, TimeUnit.SECONDS);
        }
        RbacManager user = (RbacManager) redisTemplate.opsForValue().get(token);
//        //从token中 取出账号信息
//        String userName = JWTUtil.getUserName(token);
//
//        //去数据库查出这个用户对象
//        RbacManager user = userService.getUser(userName);
        //获取数据库返回的密码
        String password = user.getPassword();
        //通过工具类 比较传入的token与数据库的账号密码是否匹配
        if (JWTUtil.verify(token,user.getAccount(),password)) {
           return new SimpleAuthenticationInfo(token,token,getName());
        }
        return null;
    }
}
